package com.gitee.wsl.io.channel.read.ext

import com.gitee.wsl.annotation.InternalAPI
import com.gitee.wsl.io.channel.ByteChannel
import com.gitee.wsl.io.channel.read.ByteReadChannel
import com.gitee.wsl.io.channel.write.ByteWriteChannel
import kotlinx.io.EOFException
import kotlinx.io.bytestring.ByteString

suspend fun ByteReadChannel.discardExact(value: Long) {
    if (discard(value) < value) throw EOFException("Unable to discard $value bytes")
}

/**
 * Suspends the channel until it is exhausted or gets closed.
 * If the read buffer is empty, it suspends until there are bytes available in the channel.
 * Once the channel is exhausted or closed, this function returns.
 *
 * @return `true` if the channel is exhausted, `false` if EOF is reached or an error occurred.
 */
@OptIn(InternalAPI::class)
suspend fun ByteReadChannel.exhausted(): Boolean {
    if (readBuffer.exhausted()) awaitContent()
    return readBuffer.exhausted()
}


/**
 * Skips the specified [byteString] in the ByteReadChannel if it is found at the current position.
 *
 * @param byteString The ByteString to look for and skip if found.
 * @return Returns `true` if the byteString was found and skipped, otherwise returns `false`.
 */
suspend fun ByteReadChannel.skipIfFound(byteString: ByteString): Boolean {
    if (peek(byteString.size) == byteString) {
        discard(byteString.size.toLong())
        return true
    }
    return false
}


@InternalAPI
fun ByteReadChannel.rethrowCloseCauseIfNeeded() {
    closedCause?.let { throw it }
}

@InternalAPI
fun ByteWriteChannel.rethrowCloseCauseIfNeeded() {
    closedCause?.let { throw it }
}

@InternalAPI
fun ByteChannel.rethrowCloseCauseIfNeeded() {
    closedCause?.let { throw it }
}